0x1 eglSwapBuffers在图形系统中的作用
在开发图形程序的时候,经常有同事问是不是调用eglSwapBuffers函数以后就可以输出显示了,如果简单来说可以这么理解,但是实际上gpu驱动中eglSwapBuffers函数执行以后只是提示上层模块该输出buffer可以使用了,这个时候是把输出buffer显示到屏幕上还是输出到文件中,或者是通过网络发送到远程终端上,取决于上层图形系统的设计。另外eglSwapBuffers函数需要配合上层模块(如Android上的Surface)完成buffer管理的工作。
本文详细介绍了eglSwapBuffers函数在图形系统中是如何配合上层buffer管理模块,完成从应用绘制到屏幕显示的完整流程的。
在典型图形系统中,一般包括了如下图所示的几个模块,应用程序绘制UI,合成器把多个UI合成为一帧图像,然后Frame buffer driver把合成好的图像绘制到屏幕硬件上。
这里有几个生产者-消费者模型,
App1/App2是UI内容的生产者,Compositor是App1/App2生产出来的UI内容的消费者,Compositor本身又是Frame buffer driver输入buffer的生产者。Frame buffer driver是Compositor生产出的buffer内容的消费者。
App1分配了三块buffer供gpu绘制使用,buffer的管理可以通过BufferQueue的模块来管理,在App1的绘制线程中调用gpu driver的eglSwapBuffers函数,eglSwapBuffers函数在执行的时候首先需要从BufferQueue中取得一块可以供GPU写入的buffer,如果这个时候没有空闲的buffer,gpu driver会在这里等待,如果发生这种情况,在性能分析的时候,我们可以在systrace上看到eglSwapBuffers占用的时间较长,从上面分析的buffer模型可以看出,出现没有空闲的buffer可能是Compositor执行太慢,三块buffer都被Compositor占用了,另外的原因可能是App1中gpu driver绘制执行时间太长,三块buffer都还在等待gpu硬件的写入完成。
eglSwapBuffers申请到了空闲的buffer以后,就可以把空闲buffer的地址设置给GPU硬件,并根据App1的其他设置驱动GPU硬件开始工作。这个时候eglSwapBuffers是否需要等待GPU硬件把完整的一帧绘制完成才返回呢?答案是不需要等待,但是会给这块buffer设置相应的fence,然后把这块buffer送给后续的Compositor来使用,Compositor在需要读取这块buffer内容之前,GPU硬件可以继续完成该buffer的绘制工作,达到CPU处理(Compositor的处理流程)和GPU处理的并行,Compositor在执行到了必须读取这块buffer内容的时候,会去检查buffer对应的fence的状态,如果还没有被signal,则需要等待,直至GPU绘制完成后singal对应的fence。
0x2 应用进程使用eglSwapBuffers
App1执行流程如下所示。
- 应用程序调用createBufferQueue创建BufferQueue,其中包括Buffer的Producer和Consumer。Producer是buffer的生产者,Consumer是buffer的消费者。这样应用中的渲染线程相当于Producer,合成器是Consumer,是buffer的消费者。
- BufferQueue通过合成器进程创建buffer队列,一般创建3个buffer。
- 渲染线程把Producer包装成Surface,然后把Surface作为参数去调用eglCreateWindowSurface。这样GPU driver相当于Producer,负责生产buffer。
- 应用程序调用draw命令,渲染线程调用eglSwapBuffers。
- eglSwapBuffers通过dequeue()查找BufferQueue中空闲的buffer,如果没有空闲的buffer则需要等待。
- eglSwapBuffers把空闲的buffer的地址设置给GPU硬件,并设置其他参数,驱动GPU硬件工作。
- eglSwapBuffers通过queue()把前面GPU的写入buffer返回给BufferQueue,并设置相应的fence。
- BufferQueue通过Consumer接口通知合成器有新的buffer到来,可以进行合成工作。
0x3 合成器进程使用eglSwapBuffers
Compositor执行流程如下所示。
这里我们只讨论采用GPU来做合成的情况,如采用2D加速硬件来做合成的话就不会在合成器中调用eglSwapBuffers。
- 应用程序创建的时候会在合成器中创建相应的Layer,这样应用程序的绘制输出就可以通知到对应的Layer。
- 创建相应的DisplayDevice,在创建DisplayDevice的时候创建BufferQueue,这里Producer是合成器线程,Consumer是后面连接的Frame buffer driver。
- 应用程序通过其渲染线程中的eglSwapBuffers通知合成器有新的buffer到来,需要进行合成工作。
- 合成器线程准备开始合成,等待应用渲染线程中的buffer被GPU硬件绘制完成。
- 合成器线程调用eglSwapBuffers。
- eglSwapBuffers通过dequeue()查找BufferQueue中空闲的buffer,如果没有空闲的buffer则需要等待。
- eglSwapBuffers通过queue()把前面GPU的写入buffer返回给BufferQueue,并设置相应的fence。
- BufferQueue通过Consumer接口通知Frame buffer driver有新的buffer到来,可以把buffer内容绘制到屏幕硬件上。
0x4 图形系统中buffer管理的特点
上面分析基本是基于Android系统的,从上面的流程可知,buffer的分配是在合成器进程中分配的,然后返回给应用进程使用。
如果是采用wayland协议的weston图形系统中,buffer的分配是在应用进程中进行的,然后把相应的buffer handle传给weston进程,作为weston合成的输入buffer使用。